package cn.yuanqiao.activiti.listener;

import cn.yuanqiao.archive.task.SyncTaskZTService;
import cn.yuanqiao.auth.util.TokenParamUtil;
import cn.yuanqiao.common.core.domain.entity.SysUser;
import cn.yuanqiao.common.utils.DateUtils;
import cn.yuanqiao.common.utils.StringUtils;
import cn.yuanqiao.common.utils.ip.IpUtils;
import cn.yuanqiao.hengtaiOrganization.service.ISOrganizationService;
import cn.yuanqiao.system.mapper.SysUserMapper;
import cn.yuanqiao.system.service.impl.SysConfigServiceImpl;
import com.alibaba.fastjson.JSONObject;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.ProcessEngines;
import org.activiti.engine.TaskService;
import org.activiti.engine.delegate.event.ActivitiEvent;
import org.activiti.engine.delegate.event.ActivitiEventListener;
import org.activiti.engine.delegate.event.impl.ActivitiEntityEventImpl;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.impl.persistence.entity.ExecutionEntityImpl;
import org.activiti.engine.impl.persistence.entity.TaskEntity;
import org.activiti.engine.task.IdentityLink;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.http.*;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * @ClassName: GlobalEventListener
 * @Description: Activiti的全局事件监听器，即所有事件均需要在这里统一分发处理
 * @author: lihuahua
 * @date: 2023/12/7 17:18
 * @Blog: huahuacoco.top
 */
@Component
public class GlobalEventListener implements ActivitiEventListener{
    /**
     * 日志处理器
     */
    public final static Log logger= LogFactory.getLog(GlobalEventListener.class);

    @Autowired
    private SyncTaskZTService remoteCommonService;

    @Autowired
    private Environment environment;

    @Autowired
    private ISOrganizationService organizationService;

    @Autowired
    private SysUserMapper userMapper;

    @Autowired
    private SysConfigServiceImpl sysConfigService;

    //事件及事件的处理器
    //更换为以下模式，可以防止Spring容器启动时，ProcessEngine尚未创建，而业务类中又使用了这个引用
    private Map<String,Object> handlers=new HashMap<String, Object>();

    @Override
    public void onEvent(ActivitiEvent event) {
        //根据事件的类型ID,找到对应的事件处理器
        ActivitiEntityEventImpl eventImpl = event instanceof ActivitiEntityEventImpl ? (ActivitiEntityEventImpl)event : null;
        if (eventImpl!=null){
            Map<String,Object> result = null;
            Map<String,Object> resultEnd = null;

            switch (event.getType()) {
                case PROCESS_STARTED:
                    // 处理流程实例启动的逻辑
                    result = processStart(eventImpl);
                    logger.info("流程实例发起:===>"+result.toString());
                    handlers.put(String.valueOf(result.get("processInstanceId")),"start");
                    //TODO 流程实例启动调用接口
                    break;
                case PROCESS_COMPLETED:
                    // 处理流程实例完成的逻辑
                    result = processEnd(eventImpl);
                    logger.info("流程实例完成:===>"+result.toString());
                    resultEnd = (Map<String, Object>) handlers.get(result.get("processInstanceId")+"taskEnd");
                    resultEnd.put("isStart",false);
                    resultEnd.put("isFinish",true);
                    syncTask(resultEnd);
                    //TODO 流程实例完成调用接口
                    //农发执行代办接口
                    nfOaDaiBan(result,resultEnd);
                    break;
                case TASK_CREATED:
                    // 处理任务实例创建的逻辑
                    result = taskStart(eventImpl);
                    logger.info("任务实例发起:===>"+result.toString());

                    //TODO 任务被分配给人的时候调用接口
                    if (handlers.containsKey(String.valueOf(result.get("processInstanceId")))){
                        result.put("isStart",true);
                        result.put("isFinish",false);
                        // 使用 TaskService 获取任务的办理人
                        TaskEntity taskEntity = (TaskEntity) eventImpl.getEntity();
                        String assignee = taskEntity.getAssignee();
                        if (assignee == null) {
                            ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
                            TaskService taskService = processEngine.getTaskService();
                            List<IdentityLink> identityLinks = taskService.getIdentityLinksForTask(taskEntity.getId());
                            for (IdentityLink link : identityLinks) {
                                if (link.getUserId() != null) {
                                    assignee = link.getUserId();
                                    result.put("assignee",assignee);
                                    break;
                                }
                            }
                        }
                        handlers.remove(String.valueOf(result.get("processInstanceId")));
                    }else {
                        resultEnd = (Map<String, Object>) handlers.get(result.get("processInstanceId")+"taskEnd");
                        resultEnd.put("isStart",false);
                        resultEnd.put("isFinish",false);
                        syncTask(resultEnd);
                        result.put("isStart",false);
                        result.put("isFinish",false);

                    }
                    //农发执行代办接口
                    nfOaDaiBan(result,resultEnd);

                    syncTask(result);
                    break;
                case TASK_COMPLETED:
                    // 处理任务实例完成的逻辑
                    result = taskEnd(eventImpl);
                    logger.info("任务实例完成:===>"+result.toString());
                    //TODO 任务办理完成的时候暂存
                    handlers.put(result.get("processInstanceId")+"taskEnd",result);
                    //remoteCommonService.syncTask(result);
                    break;
                default:
                    break;
            }
        }
    }



    public void syncTask(Map<String, Object> map) {
        //恒泰
        String hengtai_isSyncTask = environment.getProperty("HTORG.isSyncTask");
        //中铁
        String token_isSyncTask = environment.getProperty("token.isSyncTask");
        if ("true".equalsIgnoreCase(token_isSyncTask)) {
            remoteCommonService.syncTask(map);
        } else if ("true".equalsIgnoreCase(hengtai_isSyncTask)) {
            organizationService.syncTaskht(map);
        }
    }

    @Override
    public boolean isFailOnException() {
        return false;
    }

    private Map<String,Object> processStart(ActivitiEntityEventImpl eventImpl){
        String name = eventImpl.getType().name();
        ExecutionEntityImpl entity=(ExecutionEntityImpl)eventImpl.getEntity();
        ExecutionEntity parent = entity.getParent();

        Map<String, Object> logMap = new HashMap<>();

        // Extracting values from log statements and storing in the HashMap
        logMap.put("status", name);
        logMap.put("processInstanceId", parent.getProcessInstanceId());
        logMap.put("processDefinitionKey", parent.getProcessDefinitionKey());
        logMap.put("processName", parent.getName());
        logMap.put("startUserId", parent.getStartUserId());
        logMap.put("processDefinitionName", parent.getProcessDefinitionName());
        logMap.put("startTime", parent.getStartTime());
        logMap.put("tenantId", parent.getTenantId());
        return logMap;
    }

    private Map<String,Object> processEnd(ActivitiEntityEventImpl eventImpl){
        String name = eventImpl.getType().name();
        ExecutionEntityImpl entity=(ExecutionEntityImpl)eventImpl.getEntity();

        Map<String, Object> logMap = new HashMap<>();

        // Extracting values from log statements and storing in the HashMap
        logMap.put("status", name);
        logMap.put("processInstanceId", entity.getProcessInstanceId());
        logMap.put("processDefinitionKey", entity.getProcessDefinitionId().split(":")[0]);
        logMap.put("processName", entity.getName());
        logMap.put("startUserId", entity.getStartUserId());
        logMap.put("startTime", DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS,entity.getStartTime()));
        logMap.put("endTime", DateUtils.dateTimeNow(DateUtils.YYYY_MM_DD_HH_MM_SS));
        logMap.put("tenantId", entity.getTenantId());
        return logMap;
    }

    private Map<String,Object> taskStart(ActivitiEntityEventImpl eventImpl){
        String name = eventImpl.getType().name();
        TaskEntity taskEntity=(TaskEntity)eventImpl.getEntity();
        ExecutionEntity parent = taskEntity.getExecution().getParent();
        Map<String, Object> logMap = new HashMap<>();

        // Extracting values from log statements and storing in the HashMap
        logMap.put("status", name);
        logMap.put("pType","DS");
        logMap.put("assignee", taskEntity.getAssignee());
        logMap.put("taskId", taskEntity.getId());
        logMap.put("taskName", taskEntity.getName());
        logMap.put("processInstanceId", parent.getProcessInstanceId());
        logMap.put("processDefinitionKey", eventImpl.getProcessDefinitionId().split(":")[0]);
        logMap.put("processName", parent.getName());
        logMap.put("startUserId", parent.getStartUserId());
        logMap.put("processDefinitionName", parent.getProcessDefinitionName());
        logMap.put("startTime", DateUtils.dateTimeNow(DateUtils.YYYY_MM_DD_HH_MM_SS));
        logMap.put("tenantId", parent.getTenantId());
        return logMap;
    }

    private Map<String,Object> taskEnd(ActivitiEntityEventImpl eventImpl){
        String name = eventImpl.getType().name();
        TaskEntity taskEntity=(TaskEntity)eventImpl.getEntity();
        String textValueAgree = (String) taskEntity.getVariable("is_agree");
        String textValueComment = (String) taskEntity.getVariable("comment");
        ExecutionEntity parent = taskEntity.getExecution().getParent();

        Map<String, Object> logMap = new HashMap<>();

        // Extracting values from log statements and storing in the HashMap
        logMap.put("status", name);
        logMap.put("pType","YS");
        logMap.put("assignee", taskEntity.getAssignee());
        logMap.put("taskId", taskEntity.getId());
        logMap.put("taskName", taskEntity.getName());
        logMap.put("isAgree", "1".equals(textValueAgree)?"同意":"0".equals(textValueAgree)?"不同意":"2".equals(textValueAgree)?"办结":"");
        logMap.put("comment", textValueComment);
        logMap.put("processInstanceId", eventImpl.getProcessInstanceId());
        logMap.put("processDefinitionKey", eventImpl.getProcessDefinitionId().split(":")[0]);
        logMap.put("processName", parent.getName());
        logMap.put("startUserId", parent.getStartUserId());
        logMap.put("processDefinitionName", parent.getProcessDefinitionName());
        logMap.put("startTime", DateUtils.dateTimeNow(DateUtils.YYYY_MM_DD_HH_MM_SS));
        logMap.put("endTime", DateUtils.dateTimeNow(DateUtils.YYYY_MM_DD_HH_MM_SS));
        logMap.put("tenantId", parent.getTenantId());
        return logMap;
    }
    public void nfOaDaiBan(Map<String,Object> result,Map<String,Object> resultEnd) {
        try{
        String oaPath = TokenParamUtil.getOAPath();
        if(StringUtils.isEmpty(oaPath)){
            return;
        }
        String dbUser,ybUser,dbtaskId,ybtaskId;
        dbtaskId = (String)result.get("taskId");
        if (resultEnd != null) {
            ybUser = (String)resultEnd.get("assignee");
            ybtaskId = (String)resultEnd.get("taskId");
        }else {
            ybUser = "";ybtaskId ="";
        }
        dbUser = (String)result.get("assignee");
        logger.info("待办消息发送开始:::::::22::assd:::待办userid:"+dbUser+"。已办userid:"+ybUser);
        String oaUrl = oaPath+"/seeyon/rest/token";
        Map<String, String> requestBody = new HashMap<>();
        requestBody.put("userName", TokenParamUtil.getOAUname());
        requestBody.put("password", TokenParamUtil.getOAPwd());
        String postJson = postJson(oaUrl, requestBody);
        JSONObject jsonObject = JSONObject.parseObject(postJson);
        String token = jsonObject.getString("id");
            //String token ="ceshi";
        if(!"-1".equals(token)){
            if(StringUtils.isNotEmpty(dbUser)){//向OA发送待办消息
                String oaDbUrl = oaPath+"/seeyon/rest/thirdpartyPending/receive?token="+token;
                Map<String, String> requestBodyDb = new HashMap<>();
                requestBodyDb.put("taskId", dbtaskId);
                requestBodyDb.put("registerCode", TokenParamUtil.getRegisterCode());
                String title = replaceSpecialCharacters((String) result.get("processName"))+" "+result.get("startTime");
                requestBodyDb.put("title", title);//待办标题
                String dbfqrName = ybUser;//第三方待办发起人姓名
                if(StringUtils.isEmpty(ybUser)){
                    dbfqrName = (String)result.get("startUserId");
                }
                //dbfqrName
                SysUser dbfqrsysUser = userMapper.selectUserByUserNameOfAdmin(dbfqrName);
                //dbUser
                SysUser dbsysUser = userMapper.selectUserByUserNameOfAdmin(dbUser);
                //userMapper
                requestBodyDb.put("senderName", dbfqrsysUser.getNickName().trim());//第三方待办发起人姓名
                requestBodyDb.put("thirdReceiverId",dbsysUser.getRemark());//第三方待办接收人主键（保证唯一）
                String startTime = (String) result.get("startTime");
                String formatDate = DateUtils.parseDateToStr("YYYY-MM-dd",DateUtils.parseDate(startTime));
                requestBodyDb.put("creationDate", formatDate);//待办创建时间（格式：年-月-日）
                requestBodyDb.put("state", "0");//状态：0:未办理；1:已办理
                requestBodyDb.put("noneBindingSender", dbfqrsysUser.getRemark().trim());//待办发起人编号
                requestBodyDb.put("noneBindingReceiver", dbsysUser.getRemark().trim());//待办接收人编号
                String path = sysConfigService.selectConfigByKey("SYSTEM_PATH");
                requestBodyDb.put("url", path+"/task/task");//PC端穿透链接
                logger.info("待办消息推送参数requestBodyDb打印::::::::::"+requestBodyDb+";oaDbUrl====="+oaDbUrl);
                String postJsonDb  = postJson(oaDbUrl, requestBodyDb);
                JSONObject jsonObjectDb = JSONObject.parseObject(postJsonDb);
                logger.info("农发与OA待办接口返回信息打印：：：：："+jsonObjectDb.toJSONString());
            }
            if(StringUtils.isNotEmpty(ybUser)){//向OA发送已办消息
                String oaYbUrl = oaPath+"/seeyon/rest/thirdpartyPending/updatePendingState?token="+token;
                Map<String, String> requestBodyYb = new HashMap<>();
                requestBodyYb.put("taskId", ybtaskId);
                requestBodyYb.put("registerCode", TokenParamUtil.getRegisterCode());
                requestBodyYb.put("state", "1");//状态：0:未办理；1:已办理
                if(resultEnd.get("isAgree").equals("同意")){
                    requestBodyYb.put("subState", "0");//处理后状态：0/1/2/3同意已办/不同意已办/取消/驳回
                }else{
                    requestBodyYb.put("subState", "1");//处理后状态：0/1/2/3同意已办/不同意已办/取消/驳回
                }
                logger.info("已办接口推送参数requestBodyDb打印::::::::::"+requestBodyYb+";oaYbUrl====="+oaYbUrl);
                String postJsonYb  = postJson(oaYbUrl, requestBodyYb);
                JSONObject jsonObjectYb = JSONObject.parseObject(postJsonYb);
                logger.info("农发与OA已办接口返回信息打印：：：：："+jsonObjectYb.toJSONString());
            }
        }
        }catch (Exception ex) {
        logger.error("农发与OA待办/已办接口调用异常", ex);
        }

}

    public String postJson(String url, Object requestBody) {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);

        RestTemplate restTemplate = new RestTemplate();
        ResponseEntity<String> response = restTemplate.exchange(
                url,
                HttpMethod.POST,
                new HttpEntity<>(requestBody, headers),
                String.class
        );

        return response.getBody();
    }


    public static String replaceSpecialCharacters(String input) {
        if (input == null) {
            return null;
        }
        // 替换所有非字母数字下划线字符为空格
        return input.replaceAll("[^a-zA-Z0-9_\\u4e00-\\u9fa5]", " ");
    }

}
